/**
 * 地图封装类
 * 提供统一的地图创建和管理接口，支持多种地图类型切换
 */

import { Map as OlMap, View } from 'ol';
import { Tile as TileLayer } from 'ol/layer';
import { XYZ, OSM } from 'ol/source';
import { fromLonLat, toLonLat } from 'ol/proj';
import { defaults as defaultControls, Zoom, ScaleLine, MousePosition } from 'ol/control';
import { createStringXY } from 'ol/coordinate';
import { MapOptions, MapType } from '../types';
import { BaseLayer } from '../layers/BaseLayer';
import { LayerManager } from '../layers/LayerManager';
import { EventEmitter } from '../utils/event';
import { Popup } from '../overlay/Popup';
import { Marker } from '../overlay/Marker';
import { BaseControl } from '../controls/BaseControl';
import { Control } from 'ol/control';

/**
 * 地图类型配置映射
 */
const MAP_TYPE_CONFIG: Record<MapType, { url: string; attribution?: string }> = {
  [MapType.GAODE]: {
    url: 'https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
    attribution: '高德地图'
  },
  [MapType.BAIDU]: {
    url: 'https://shangetu{s}.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46',
    attribution: '百度地图'
  },
  [MapType.TENCENT]: {
    url: 'https://rt{s}.map.gtimg.com/tile?z={z}&x={x}&y={y}&type=vector&styleid=3',
    attribution: '腾讯地图'
  },
  [MapType.OSM]: {
    url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    attribution: 'OpenStreetMap'
  },
  [MapType.TIANDITU]: {
    url: 'https://t{s}.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=YOUR_KEY',
    attribution: '天地图'
  },
  [MapType.CUSTOM]: {
    url: ''
  }
};

/**
 * 地图封装类
 */
export class Map extends EventEmitter {
  /** OpenLayers地图实例 */
  private olMap: OlMap | null = null;
  /** 当前地图类型 */
  private currentMapType: MapType;
  /** 底图图层 */
  private baseLayer: TileLayer<XYZ | OSM> | null = null;
  /** 所有图层 */
  private layers: globalThis.Map<string, BaseLayer> = new globalThis.Map();
  /** 图层管理器 */
  private layerManager: LayerManager;
  /** 所有弹窗 */
  private popups: globalThis.Map<string, Popup> = new globalThis.Map();
  /** 所有标记点 */
  private markers: globalThis.Map<string, Marker> = new globalThis.Map();
  /** 所有控件 */
  private controls: globalThis.Map<string, BaseControl> = new globalThis.Map();
  /** 扩展管理器 */
  private extensions: globalThis.Map<string, any> = new globalThis.Map();
  /** 地图配置 */
  private options: MapOptions;

  /**
   * 构造函数
   * @param options 地图配置
   */
  constructor(options: MapOptions) {
    super();
    this.options = {
      center: [116.397428, 39.90923], // 默认北京
      zoom: 10,
      mapType: MapType.GAODE,
      controls: true,
      zoomControl: true,
      scaleLine: false,
      mousePosition: false,
      projection: 'EPSG:3857',
      ...options
    };
    this.currentMapType = this.options.mapType || MapType.GAODE;
    this.layerManager = new LayerManager();
    this.init();
  }

  /**
   * 初始化地图
   */
  private init(): void {
    const { target, center, zoom, minZoom, maxZoom, controls, zoomControl, scaleLine, mousePosition } = this.options;

    // 创建底图图层
    this.createBaseLayer();

    // 创建控件
    const controlList: any[] = [];
    
    if (zoomControl) {
      controlList.push(new Zoom());
    }
    
    if (scaleLine) {
      controlList.push(new ScaleLine());
    }
    
    if (mousePosition) {
      controlList.push(
        new MousePosition({
          coordinateFormat: createStringXY(4),
          projection: 'EPSG:4326'
        })
      );
    }

    // 创建地图视图
    const view = new View({
      center: center ? fromLonLat(center) : undefined,
      zoom,
      minZoom,
      maxZoom,
      projection: this.options.projection
    });

    // 创建OpenLayers地图实例
    this.olMap = new OlMap({
      target: typeof target === 'string' ? document.getElementById(target) || target : target,
      layers: this.baseLayer ? [this.baseLayer] : [],
      view,
      controls: controls ? defaultControls().extend(controlList) : defaultControls({ zoom: false })
    });

    // 监听地图事件
    this.olMap.on('moveend', () => {
      this.emit('moveend', this.getCenter(), this.getZoom());
    });

    this.olMap.on('zoomend' as any, () => {
      this.emit('zoomend', this.getZoom());
    });

    this.olMap.on('click', (event: any) => {
      this.emit('click', event);
    });

    this.emit('ready', this);
  }

  /**
   * 创建底图图层
   */
  private createBaseLayer(): void {
    const config = MAP_TYPE_CONFIG[this.currentMapType];
    let url = config.url;

    // 如果是自定义类型，使用用户提供的URL
    if (this.currentMapType === MapType.CUSTOM && this.options.tileUrl) {
      url = this.options.tileUrl;
    }

    // 如果已有底图图层，更新其 source 而不是重新创建
    if (this.baseLayer && this.olMap) {
      let newSource: XYZ | OSM;
      
      if (!url) {
        // 如果没有URL，使用OSM作为默认底图
        newSource = new OSM();
      } else {
        // 处理子域名占位符
        let processedUrl = url;
        const subdomains: string[] = [];
        
        if (url.includes('{s}')) {
          subdomains.push('1', '2', '3', '4');
          processedUrl = url.replace('{s}', '{s}');
        } else if (url.includes('{a-c}')) {
          subdomains.push('a', 'b', 'c');
          processedUrl = url.replace('{a-c}', '{s}');
        }

        // 创建XYZ瓦片源
        newSource = new XYZ({
          url: processedUrl,
          urls: subdomains.length > 0 ? subdomains.map(sub => processedUrl.replace('{s}', sub)) : undefined,
          attributions: config.attribution
        });
      }

      // 更新现有图层的 source
      this.baseLayer.setSource(newSource);
      return;
    }

    // 创建新的底图图层
    if (!url) {
      // 如果没有URL，使用OSM作为默认底图
      this.baseLayer = new TileLayer({
        source: new OSM()
      });
      return;
    }

    // 处理子域名占位符
    let processedUrl = url;
    const subdomains: string[] = [];
    
    if (url.includes('{s}')) {
      subdomains.push('1', '2', '3', '4');
      processedUrl = url.replace('{s}', '{s}');
    } else if (url.includes('{a-c}')) {
      subdomains.push('a', 'b', 'c');
      processedUrl = url.replace('{a-c}', '{s}');
    }

    // 创建XYZ瓦片源
    const source = new XYZ({
      url: processedUrl,
      urls: subdomains.length > 0 ? subdomains.map(sub => processedUrl.replace('{s}', sub)) : undefined,
      attributions: config.attribution
    });

    this.baseLayer = new TileLayer({
      source
    });
  }

  /**
   * 切换地图类型
   * @param mapType 地图类型
   * @param tileUrl 自定义瓦片地址（可选）
   */
  setMapType(mapType: MapType, tileUrl?: string): void {
    if (mapType === this.currentMapType && !tileUrl) {
      return;
    }

    this.currentMapType = mapType;
    if (tileUrl) {
      this.options.tileUrl = tileUrl;
    }

    // 如果已有底图，直接更新 source
    if (this.baseLayer && this.olMap) {
      this.createBaseLayer();
      // 触发地图重新渲染
      this.olMap.render();
    } else {
      // 如果没有底图，创建新的
      this.createBaseLayer();
      if (this.baseLayer && this.olMap) {
        this.olMap.getLayers().insertAt(0, this.baseLayer);
      }
    }

    this.emit('maptypechange', mapType);
  }

  /**
   * 获取当前地图类型
   * @returns 地图类型
   */
  getMapType(): MapType {
    return this.currentMapType;
  }

  /**
   * 添加图层
   * @param layer 图层实例
   * @param isTemp 是否为临时图层
   */
  addLayer(layer: BaseLayer, isTemp: boolean = false): void {
    if (!this.olMap) {
      throw new Error('Map not initialized');
    }

    const layerId = layer.getId() || `layer_${Date.now()}`;
    if (!layer.getId()) {
      layer.updateOptions({ id: layerId });
    }

    layer.init(this.olMap);
    this.layers.set(layerId, layer);
    
    // 注册到图层管理器
    this.layerManager.registerLayer(layerId, layer, isTemp);

    // 监听图层销毁事件
    layer.once('destroy', () => {
      this.layers.delete(layerId);
    });

    this.emit('layeradd', layer);
  }

  /**
   * 移除图层
   * @param layerId 图层ID或图层实例
   */
  removeLayer(layerId: string | BaseLayer): void {
    let layer: BaseLayer | undefined;
    let id: string | undefined;

    if (typeof layerId === 'string') {
      layer = this.layers.get(layerId);
      id = layerId;
    } else {
      layer = layerId;
      id = layer.getId();
    }

    if (layer && id) {
      // 通过图层管理器移除
      this.layerManager.removeLayer(id);
      layer.destroy();
      this.layers.delete(id);
      this.emit('layerremove', layer);
    }
  }

  /**
   * 获取图层管理器
   * @returns 图层管理器实例
   */
  getLayerManager(): LayerManager {
    return this.layerManager;
  }

  /**
   * 显示/隐藏图层分组
   * @param groupName 分组名称
   * @param visible 是否可见
   */
  setGroupVisibility(groupName: string, visible: boolean): void {
    this.layerManager.setGroupVisibility(groupName, visible);
  }

  /**
   * 清理所有临时图层
   */
  clearTempLayers(): void {
    this.layerManager.clearTempLayers();
  }

  /**
   * 根据角色设置图层权限
   * @param role 角色名称
   * @param permissions 权限配置
   */
  setLayerPermissionsByRole(
    role: string,
    permissions: { [layerId: string]: { visible: boolean; editable: boolean } }
  ): void {
    this.layerManager.setLayerPermissionsByRole(role, permissions);
  }

  /**
   * 获取图层
   * @param layerId 图层ID
   * @returns 图层实例
   */
  getLayer(layerId: string): BaseLayer | undefined {
    return this.layers.get(layerId);
  }

  /**
   * 获取所有图层
   * @returns 图层数组
   */
  getAllLayers(): BaseLayer[] {
    return Array.from(this.layers.values());
  }

  /**
   * 设置地图中心点
   * @param center 中心点坐标 [经度, 纬度]
   * @param duration 动画时长（毫秒）
   */
  setCenter(center: [number, number], duration?: number): void {
    if (!this.olMap) return;

    const view = this.olMap.getView();
    const coordinate = fromLonLat(center);

    if (duration) {
      // 修复animate方法类型错误
      view.animate({
        center: coordinate,
        duration: duration
      } as any);
    } else {
      view.setCenter(coordinate);
    }
  }

  /**
   * 获取地图中心点
   * @returns 中心点坐标 [经度, 纬度]
   */
  getCenter(): [number, number] {
    if (!this.olMap) {
      return this.options.center || [0, 0];
    }

    const view = this.olMap.getView();
    const center = view.getCenter();
    if (!center) {
      return this.options.center || [0, 0];
    }

    return toLonLat(center) as [number, number];
  }

  /**
   * 设置缩放级别
   * @param zoom 缩放级别
   * @param duration 动画时长（毫秒）
   */
  setZoom(zoom: number, duration?: number): void {
    if (!this.olMap) return;

    const view = this.olMap.getView();

    if (duration) {
      // 修复animate方法类型错误
      view.animate({
        zoom: zoom,
        duration: duration
      } as any);
    } else {
      view.setZoom(zoom);
    }
  }

  /**
   * 获取缩放级别
   * @returns 缩放级别
   */
  getZoom(): number {
    if (!this.olMap) {
      return this.options.zoom || 10;
    }

    return this.olMap.getView().getZoom() || this.options.zoom || 10;
  }

  /**
   * 缩放到指定范围
   * @param extent 范围 [minX, minY, maxX, maxY] (经纬度)
   * @param duration 动画时长（毫秒）
   */
  fitExtent(extent: [number, number, number, number], duration?: number): void {
    if (!this.olMap) return;

    // 转换范围为EPSG:3857坐标
    const minCoord = fromLonLat([extent[0], extent[1]]);
    const maxCoord = fromLonLat([extent[2], extent[3]]);
    const olExtent: [number, number, number, number] = [
      minCoord[0],
      minCoord[1],
      maxCoord[0],
      maxCoord[1]
    ];

    const view = this.olMap.getView();
    if (duration) {
      view.fit(olExtent, {
        duration,
        padding: [50, 50, 50, 50]
      });
    } else {
      view.fit(olExtent, {
        padding: [50, 50, 50, 50]
      });
    }
  }

  /**
   * 获取OpenLayers地图实例
   * @returns OpenLayers地图实例
   */
  getOlMap(): OlMap | null {
    return this.olMap;
  }

  /**
   * 获取地图视图
   * @returns 地图视图
   */
  getView(): View | null {
    return this.olMap?.getView() || null;
  }

  /**
   * 更新地图大小（当容器大小改变时调用）
   */
  updateSize(): void {
    if (this.olMap) {
      this.olMap.updateSize();
    }
  }

  /**
   * 添加弹窗
   * @param popup 弹窗实例
   */
  addPopup(popup: Popup): void {
    if (!this.olMap) {
      throw new Error('Map not initialized');
    }

    const popupId = popup.getId() || `popup_${Date.now()}`;
    this.popups.set(popupId, popup);
    this.emit('popupadd', popup);
  }

  /**
   * 移除弹窗
   * @param popupId 弹窗ID或弹窗实例
   */
  removePopup(popupId: string | Popup): void {
    let popup: Popup | undefined;

    if (typeof popupId === 'string') {
      popup = this.popups.get(popupId);
    } else {
      popup = popupId;
      popupId = popup.getId() || '';
    }

    if (popup) {
      popup.close();
      if (typeof popupId === 'string' && popupId) {
        this.popups.delete(popupId);
      }
      this.emit('popupremove', popup);
    }
  }

  /**
   * 添加标记点
   * @param marker 标记点实例
   */
  addMarker(marker: Marker): void {
    if (!this.olMap) {
      throw new Error('Map not initialized');
    }

    const markerId = marker.getId() || `marker_${Date.now()}`;
    marker.addTo(this.olMap);
    this.markers.set(markerId, marker);
    this.emit('markeradd', marker);
  }

  /**
   * 移除标记点
   * @param markerId 标记点ID或标记点实例
   */
  removeMarker(markerId: string | Marker): void {
    let marker: Marker | undefined;

    if (typeof markerId === 'string') {
      marker = this.markers.get(markerId);
    } else {
      marker = markerId;
      markerId = marker.getId() || '';
    }

    if (marker) {
      marker.remove();
      if (typeof markerId === 'string' && markerId) {
        this.markers.delete(markerId);
      }
      this.emit('markerremove', marker);
    }
  }

  /**
   * 添加控件
   * @param control 控件实例
   */
  addControl(control: BaseControl): void {
    if (!this.olMap) {
      throw new Error('Map not initialized');
    }

    const controlId = `control_${Date.now()}`;
    const olControl = control.getControl();
    this.olMap.addControl(olControl);
    this.controls.set(controlId, control);
    this.emit('controladd', control);
  }

  /**
   * 移除控件
   * @param control 控件实例
   */
  removeControl(control: BaseControl): void {
    if (!this.olMap) return;

    const olControl = control.getControl();
    this.olMap.removeControl(olControl);
    
    // 从 Map 中移除
    for (const [id, ctrl] of this.controls.entries()) {
      if (ctrl === control) {
        this.controls.delete(id);
        break;
      }
    }
    
    this.emit('controlremove', control);
  }

  /**
   * 获取所有弹窗
   * @returns 弹窗数组
   */
  getAllPopups(): Popup[] {
    return Array.from(this.popups.values());
  }

  /**
   * 获取所有标记点
   * @returns 标记点数组
   */
  getAllMarkers(): Marker[] {
    return Array.from(this.markers.values());
  }

  /**
   * 关闭所有弹窗
   */
  closeAllPopups(): void {
    this.popups.forEach((popup) => {
      popup.close();
    });
  }

  /**
   * 清除所有标记点
   */
  clearAllMarkers(): void {
    this.markers.forEach((marker) => {
      marker.remove();
    });
    this.markers.clear();
  }

  /**
   * 注册扩展
   * @param name 扩展名称
   * @param extension 扩展实例
   */
  registerExtension(name: string, extension: any): void {
    this.extensions.set(name, extension);
    this.emit('extensionRegistered', name, extension);
  }

  /**
   * 获取扩展
   * @param name 扩展名称
   */
  getExtension(name: string): any | undefined {
    return this.extensions.get(name);
  }

  /**
   * 移除扩展
   * @param name 扩展名称
   */
  removeExtension(name: string): boolean {
    const removed = this.extensions.delete(name);
    if (removed) {
      this.emit('extensionRemoved', name);
    }
    return removed;
  }

  /**
   * 获取所有扩展
   */
  getAllExtensions(): ReadonlyMap<string, any> {
    return this.extensions;
  }

  /**
   * 销毁地图
   */
  destroy(): void {
    // 销毁所有图层
    this.layers.forEach((layer: BaseLayer) => {
      layer.destroy();
    });
    this.layers.clear();

    // 销毁所有弹窗
    this.popups.forEach((popup) => {
      popup.destroy();
    });
    this.popups.clear();

    // 销毁所有标记点
    this.markers.forEach((marker) => {
      marker.destroy();
    });
    this.markers.clear();

    // 销毁所有扩展
    this.extensions.forEach((extension, name) => {
      if (extension.destroy) {
        extension.destroy();
      }
    });
    this.extensions.clear();

    // 销毁地图
    if (this.olMap) {
      this.olMap.setTarget(undefined);
      this.olMap = null;
    }

    this.baseLayer = null;
    this.removeAllListeners();
    this.emit('destroy', this);
  }
}

